﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Comp376A2_9609695
{
    /// <summary>
    /// The pump DigDug throws
    /// </summary>
    class Pump : Monster, Drawable
    {
        private float length = 0;
        public DigDug.Direction facing;
        private int maxLength = 48;
        public SpriteSheet spritesheet;
        private bool stopped;
        private Monster monster;
        public bool isStopped { get { return stopped; } }

        public Pump(int startX, int startY, DigDug.Direction direction)
        {
            speed = 32;
            position = new Vector2(startX, startY);
            startPos = new Vector2(startX, startY);
            facing = direction;
            switch (facing)
            {
                case DigDug.Direction.Left:
                    position.X -= 3;
                    break;
                case DigDug.Direction.Right:
                    position.X += 3;
                    break;
                case DigDug.Direction.Up:
                    position.Y -= 3;
                    break;
                case DigDug.Direction.Down:
                    position.Y += 3;
                    break;
                default:
                    break;
            }
        }

        public override void update(GameTime time, GameController control)
        {
            int elapsed = time.ElapsedGameTime.Milliseconds + 1;
            // If the pump is moving and alive
            if (!stopped && !dead)
            {
                Vector2 velocity = new Vector2();
                Vector2 adjPos = new Vector2((int)Math.Floor(position.X - control.level.X), (int)Math.Floor(position.Y - control.level.Y));
                if (facing == DigDug.Direction.Right)
                    adjPos.X += 16;
                if (facing == DigDug.Direction.Down)
                    adjPos.Y += 16;
                byte cell = control.level.getCellAt((int)adjPos.X, (int)adjPos.Y);
                // If the adjacent cell is not filled, let the pump go into it
                if (cell != 0)
                {
                    switch (facing)
                    {
                        case DigDug.Direction.Left:
                            if (adjPos.X % 16 > 0 || (cell & 1) != 0)
                            {
                                byte nextCell = control.level.getCellAt((int)(adjPos.X - speed / elapsed), (int)adjPos.Y);
                                // If the position is not at a wall or the next wall is cleared, move
                                if ((adjPos.X % 16 > 2 && adjPos.X % 16 < 14) || (nextCell & 4) != 0)
                                    velocity.X = -1;
                            }
                            break;
                        case DigDug.Direction.Right:
                            if (adjPos.X % 16 > 0 || (cell & 4) != 0)
                            {
                                byte nextCell = control.level.getCellAt((int)(adjPos.X + speed / elapsed), (int)adjPos.Y);
                                if ((adjPos.X % 16 > 2 && adjPos.X % 16 < 14) || (nextCell & 1) != 0)
                                    velocity.X = 1;
                            }
                            break;
                        case DigDug.Direction.Up:
                            if (adjPos.Y % 16 > 0 || (cell & 2) != 0)
                            {
                                byte nextCell = control.level.getCellAt((int)adjPos.X, (int)(adjPos.Y - speed / elapsed));
                                if ((adjPos.Y % 16 > 2 && adjPos.Y % 16 < 14) || (nextCell & 8) != 0)
                                    velocity.Y = -1;
                            }
                            break;
                        case DigDug.Direction.Down:
                            if (adjPos.Y % 16 > 0 || (cell & 8) != 0)
                            {
                                byte nextCell = control.level.getCellAt((int)adjPos.X, (int)(adjPos.Y - speed / elapsed));
                                if ((adjPos.Y % 16 > 2 && adjPos.Y % 16 < 14) || (nextCell & 2) != 0)
                                    velocity.Y = 1;
                            }
                            break;
                        default:
                            break;
                    }
                }
                position.X += velocity.X * speed / elapsed;
                position.Y += velocity.Y * speed / elapsed;
                length += Math.Abs(velocity.X * speed / elapsed) + Math.Abs(velocity.Y * speed / elapsed);
                // If the length is at the max length, kill the pump
                if (length >= maxLength || (velocity.X == 0 && velocity.Y == 0))
                {
                    dead = true;
                }
            }
        }

        public Texture2D getImage()
        {
            return spritesheet.image;
        }

        public void draw(SpriteBatch renderer)
        {
            if (!dead)
            {
                int intLen = (int)Math.Ceiling(length);
                int lengthToDraw = intLen;
                int gridLengths = 0;
                // If there's still some hose to draw, draw it
                while (lengthToDraw > 0)
                {
                    int xPos = 0, yPos = 0, width = 0, height = 0, drawLen;
                    // If there is more than a full cell to draw, draw one cell
                    if (lengthToDraw >= 16)
                    {
                        drawLen = 16;
                    }
                    // Otherwise, draw the rest
                    else
                    {
                        drawLen = lengthToDraw;
                    }
                    switch (facing)
                    {
                        case DigDug.Direction.Left:
                            xPos = (int)startPos.X - 16 * (gridLengths) - drawLen;
                            yPos = (int)startPos.Y + 6;
                            width = drawLen;
                            height = 8;
                            break;
                        case DigDug.Direction.Right:
                            xPos = (int)startPos.X + 16 * (gridLengths + 1);
                            yPos = (int)startPos.Y + 6;
                            width = drawLen;
                            height = 8;
                            break;
                        case DigDug.Direction.Up:
                            xPos = (int)startPos.X + 6;
                            yPos = (int)startPos.Y - 16 * (gridLengths) - drawLen;
                            width = 8;
                            height = drawLen;
                            break;
                        case DigDug.Direction.Down:
                            xPos = (int)startPos.X + 4;
                            yPos = (int)startPos.Y + 16 * (gridLengths + 1);
                            width = 8;
                            height = drawLen;
                            break;
                        default:
                            break;
                    }
                    Rectangle dest = new Rectangle(xPos, yPos, width, height);
                    Rectangle source;
                    switch (facing)
                    {
                        case DigDug.Direction.Left:
                            source = spritesheet.getSprite(0);
                            source.Width = drawLen;
                            source.X = 16 - drawLen;
                            break;
                        case DigDug.Direction.Up:
                            source = spritesheet.getSprite(1);
                            source.Height = drawLen;
                            source.Y = 16 - drawLen;
                            break;
                        case DigDug.Direction.Right:
                            source = spritesheet.getSprite(0);
                            source.Width = drawLen;
                            break;
                        case DigDug.Direction.Down:
                            source = spritesheet.getSprite(1);
                            source.Height = drawLen;
                            break;
                        default:
                            source = new Rectangle();
                            break;
                    }
                    renderer.Draw(spritesheet.image, dest, source, Color.White);

                    // Draw the tip at the end
                    switch (facing)
                    {
                        case DigDug.Direction.Left:
                            xPos = (int)startPos.X - intLen - 3;
                            yPos = (int)startPos.Y + 6;
                            width = 3;
                            height = 8;
                            source = spritesheet.getSprite(2);
                            break;
                        case DigDug.Direction.Right:
                            xPos = (int)startPos.X + intLen + 16;
                            yPos = (int)startPos.Y + 6;
                            width = 3;
                            height = 8;
                            source = spritesheet.getSprite(4);
                            break;
                        case DigDug.Direction.Up:
                            xPos = (int)startPos.X + 6;
                            yPos = (int)startPos.Y - intLen - 3;
                            width = 8;
                            height = 3;
                            source = spritesheet.getSprite(3);
                            break;
                        case DigDug.Direction.Down:
                            xPos = (int)startPos.X + 4;
                            yPos = (int)startPos.Y + intLen + 16;
                            width = 8;
                            height = 5;
                            source = spritesheet.getSprite(5);
                            break;
                        default:
                            break;
                    }
                    dest = new Rectangle(xPos, yPos, width, height); ;
                    renderer.Draw(spritesheet.image, dest, source, Color.White);

                    if (drawLen == 16)
                        gridLengths++;
                    // Remove the amount of hose drawn from the amount remaining
                    lengthToDraw -= drawLen;
                }
            }
        }

        public override void reset()
        {
            // Kill the pump on reset
            dead = true;
        }

        /// <summary>
        /// Attach the pump to a monster
        /// </summary>
        /// <param name="monster">The monster to attach to</param>
        public void attach(Monster monster)
        {
            this.monster = monster;
        }

        /// <summary>
        /// Detach the pump from a monster
        /// </summary>
        /// <param name="monster">The monster to detach from</param>
        public void detach(Monster monster)
        {
            if (this.monster != null && this.monster.Equals(monster))
                this.monster = null;
        }

        /// <summary>
        /// Pump the pump
        /// </summary>
        public void pump()
        {
            if (length < maxLength)
                monster.pump();
        }

        /// <summary>
        /// Stop the pump from being thrown
        /// </summary>
        public void stop()
        {
            stopped = true;
        }

        /// <summary>
        /// Kill the pump
        /// </summary>
        public void kill()
        {
            dead = true;
        }
    }
}
